package com.supermap.fabricsdk;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.PKCS8Generator;
import org.bouncycastle.openssl.jcajce.*;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.bouncycastle.pkcs.PKCSException;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.List;

/**
 * @author liqs
 * @version 1.0
 * @date 2020/6/15 13:38
 *
 * 主要为解析日志审查服务
 */
public class SmUtils {

    // 区块链证书进行解码得到证书的组织信息
    public JSONObject getUserInfo(File pemFile){
        JSONObject json = new JSONObject();
        String s = testOu(pemFile);
        try {
            InputStream inputStream = new ByteArrayInputStream(s.getBytes());
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate certificate = (X509Certificate) cf.generateCertificate(inputStream);
            Principal principal = certificate.getSubjectDN();
            String principalName = principal.getName();// 这里面获取具体的用户名
            Principal issuerDN = certificate.getIssuerDN();   // 这里面获取组织
            String issuerDNName = issuerDN.getName();
            String user = getUser(principalName);
            String org = getOrg(issuerDNName);
            json.put("Org", org);
            json.put("User", user);
        } catch (CertificateException E){

        }
        return json;
    }

    // 区块链证书进行解码得到证书的组织信息
    public X509Certificate getcertificate(File pemFile){
        X509Certificate certificate = null;
        String s = testOu(pemFile);
        try {
            InputStream inputStream = new ByteArrayInputStream(s.getBytes());
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            certificate = (X509Certificate) cf.generateCertificate(inputStream);
        } catch (CertificateException E){

        }
        return certificate;
    }

    // 读取文件得到证书信息的 String 信息
    private String testOu(File pemFile){
        StringBuilder stringBuilder = new StringBuilder();
        // 写到临时文件
        try {
            String initString = FileUtils.readFileToString(pemFile);
            String[] strings = initString.split("\n");
            FileWriter fw = new FileWriter("out.pem");
            int line = 1;
            for (String s : strings) {
                if (line == 1) {
                    fw.write("-----BEGIN CERTIFICATE-----" + "\n");             // 一行行获取数据的一种方式
                    stringBuilder.append("-----BEGIN CERTIFICATE-----" + "\n");     // 因为是换行，所以采用StringBuilder追加形成
                } else {
                    fw.write(s + "\n");
                    stringBuilder.append(s + "\n");
                }
                line++;
            }
            fw.close();
        }catch (Exception E){
        }
        return stringBuilder.toString();
    }

    // 获取用户信息
    private String getUser(String str){
        List<String> result = Arrays.asList(str.split(","));
        String cn = result.get(0);
        cn = cn.trim();
        while (cn.startsWith("　")) {
            cn = cn.substring(1, cn.length()).trim();
        }
        return cn.substring(3, cn.length());
    }

    // 获取组织信息
    private String getOrg(String str){
        List<String> result = Arrays.asList(str.split(","));
        String cn = result.get(1);
        cn = cn.trim();
        while (cn.startsWith("　")) {
            cn = cn.substring(1, cn.length()).trim();
        }
        return cn.substring(2, cn.length());
    }

    //将证书保存到本地文件
    public static String pemFrom(X509Certificate x509Certificate) throws IOException, CertificateEncodingException {
        PemObject pem = new PemObject("CERTIFICATE", x509Certificate.getEncoded());
        StringWriter str = new StringWriter();
        PemWriter pemWriter = new PemWriter(str);
        pemWriter.writeObject(pem);
        pemWriter.close();
        str.close();
        return str.toString();
    }

    public static String pemFrom(PrivateKey privateKey, String password) throws OperatorCreationException, IOException {
        OutputEncryptor encryptor = null;
        if (password != null && password.length() > 0) {
            encryptor = new JceOpenSSLPKCS8EncryptorBuilder(PKCS8Generator.AES_256_CBC)
                    .setProvider(BouncyCastleProvider.PROVIDER_NAME)
                    .setRandom(new SecureRandom())
                    .setPasssword(password.toCharArray())
                    .build();
        }
        PKCS8Generator generator = new JcaPKCS8Generator(privateKey, encryptor);
        StringWriter stringWriter = new StringWriter();
        JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter);
        pemWriter.writeObject(generator);
        pemWriter.close();
        stringWriter.close();
        return stringWriter.toString();
    }

    public static String pemFrom(PublicKey publicKey) throws IOException {
        PemObject pem = new PemObject("PUBLIC KEY", publicKey.getEncoded());
        StringWriter str = new StringWriter();
        PemWriter pemWriter = new PemWriter(str);
        pemWriter.writeObject(pem);
        pemWriter.close();
        str.close();
        return str.toString();
    }

    public static PrivateKey loadPrivFromFile(String filename, String password) throws IOException, OperatorCreationException, PKCSException {
        FileReader fr = new FileReader(filename);
        PEMParser pemReader = new PEMParser(fr);
        Object obj = pemReader.readObject();
        fr.close();
        pemReader.close();
        JcaPEMKeyConverter CONVERTER = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);
        if (password != null && password.length() > 0) {
            if (obj instanceof PKCS8EncryptedPrivateKeyInfo) {
                PKCS8EncryptedPrivateKeyInfo epkInfo = (PKCS8EncryptedPrivateKeyInfo) obj;
                InputDecryptorProvider decryptor = new JceOpenSSLPKCS8DecryptorProviderBuilder()
                        .setProvider(BouncyCastleProvider.PROVIDER_NAME)
                        .build(password.toCharArray());
                PrivateKeyInfo pkInfo = epkInfo.decryptPrivateKeyInfo(decryptor);
                return CONVERTER.getPrivateKey(pkInfo);
            }
        } else {
            return CONVERTER.getPrivateKey((PrivateKeyInfo) obj);
        }
        return null;
    }

    public static X509Certificate loadX509CertificateFromFile(String filename) throws IOException, CertificateException,
            NoSuchProviderException {
        FileInputStream in = null;
        try {
            in = new FileInputStream(filename);
            CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
            return (X509Certificate) cf.generateCertificate(in);
        } finally {
            in.close();
        }
    }
}
